Skip to content

[Android] Send Native Crash reports with empty stacktraces for OS 11#934

Open
Copilot wants to merge 2 commits intomainfrom
copilot/implement-skeleton-crash-reports
Open

[Android] Send Native Crash reports with empty stacktraces for OS 11#934
Copilot wants to merge 2 commits intomainfrom
copilot/implement-skeleton-crash-reports

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

What

Resolves BIT-7817

Adds support for generating native-crash reports on Android API 30 without stacktraces when ApplicationExitInfo.getTraceInputStream() returns null, avoiding silently dropping those crashes.

Will rely on status from AppExit which is set here

Verification

With OS 11 emulator trigger random native crash on gradle-test-app

Trigger same crash NATIVE_CAPTURE_DESTROY_CRASH on both OS levels

Screenshot 2026-04-09 at 13 15 39
  • CHANGELOG.md's "Unreleased" section has been updated, if applicable.

Copilot AI changed the title [WIP] Implement skeleton crash reports without stack traces for native crashes BIT-7817: Skeleton crash reports for native crashes on API level 30 Apr 8, 2026
Copilot finished work on behalf of murki April 8, 2026 21:54
Copilot AI requested a review from murki April 8, 2026 21:54
@murki murki requested a review from Copilot April 8, 2026 21:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for generating “skeleton” native-crash reports on Android API 30 when ApplicationExitInfo.getTraceInputStream() returns null, avoiding silently dropping those crashes.

Changes:

  • Make processAppExitReport(..., traceInputStream) nullable through IIssueReporterProcessor/IssueReporterProcessor.
  • Update IssueReporter to always invoke .use {} on the (nullable) trace stream and forward it to the processor.
  • Add NativeCrashProcessor fallback to build a minimal native-crash Report when tombstone data is unavailable, plus a regression test and changelog entry.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/IssueReporter.kt Routes app-exit processing through a single .use {} path that can forward a null stream.
platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/IIssueReporterProcessor.kt Updates API contract to accept a nullable trace stream (defaulting to null).
platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/IssueReporterProcessor.kt Propagates nullable stream into native crash processing and ANR processing path.
platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/NativeCrashProcessor.kt Generates a skeleton native crash report when tombstone stream is null.
platform/jvm/capture/src/test/kotlin/io/bitdrift/capture/reports/processor/IssueReporterProcessorTest.kt Adds test coverage for the new skeleton-report behavior.
CHANGELOG.md Documents the API-30 native-crash reporting fix.
Comments suppressed due to low confidence (1)

platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/IssueReporterProcessor.kt:117

  • traceInputStream is now nullable, but the ANR branch passes it directly to processAndPersistANR(stream: InputStream, ...), which requires a non-null stream. This is a compile-time type mismatch (and would also be a runtime issue if forced). Consider requiring a non-null stream when fatalIssueType == ReportType.AppNotResponding (e.g., val stream = requireNotNull(traceInputStream) with a clear error/log + early return) while keeping null allowed for native crashes.
        traceInputStream: InputStream?,
    ) {
        runCatching {
            if (fatalIssueType == ReportType.AppNotResponding) {
                streamingReportsProcessor.processAndPersistANR(
                    traceInputStream,
                    timestamp,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot stopped work on behalf of murki due to an error April 8, 2026 22:06
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

Size Comparison Report (x86_64)

Metric APK (KB) SO (KB)
Baseline 3406 1280
Current 3411 1280
Difference 5 0

APK size increased by 5 KB. SO size unchanged.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 8, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dl.google.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx2048M -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of murki April 8, 2026 22:30
Copilot AI requested a review from murki April 8, 2026 22:30
@murki
Copy link
Copy Markdown
Contributor

murki commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 8, 2026

@copilot apply changes based on the comments in this thread

Removed the = null default from traceInputStream in IIssueReporterProcessor so callers must pass it explicitly. All existing call sites already pass it explicitly. See 64ccb05.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dl.google.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx2048M -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of murki April 8, 2026 22:57
@murki murki requested a review from Copilot April 8, 2026 23:02
@murki murki marked this pull request as ready for review April 8, 2026 23:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/NativeCrashProcessor.kt:206

  • description is nullable, but signalName.ifEmpty { description } requires a non-null fallback string. As written, this won’t compile (or would risk passing null into createString). Use a non-null default (e.g., description ?: "Native crash") for the empty-signal case so the error name/reason is always a valid string.
        tombstone: Tombstone,
        frameOffsets: IntArray,
    ): Int {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

Android Benchmark Results

Device: PR: Emulator - Android SDK built for x86_64 (API 31) | main: Emulator - Android SDK built for x86_64 (API 31)

Note: Benchmarks run on emulator. Results may vary between runs and may differ from physical devices.

Allocations

Test PR main Δ
logHttpNetworkLog50FieldsAndHeadersAndFieldProviders 923 924 -0.1%
logNotMatched5000Fields 10 10 0.0%
logNotMatchedNoFields 1 1 0.0%
trackSpansWithFields 140 140 0.0%
trackSpansWithoutFields 55 55 0.0%
webViewBridgeBridgeReady 61 61 0.0%
webViewBridgeCustomLog 66 66 0.0%
webViewBridgeInvalidJson 38 38 0.0%
webViewBridgeWebVitalCLS 177 178 -0.6%

Timing

Test PR main Δ
logHttpNetworkLog50FieldsAndHeadersAndFieldProviders 238.57 us 235.02 us +1.5%
logNotMatched5000Fields 2.44 ms 2.44 ms 0.0%
logNotMatchedNoFields 461 ns 469 ns -1.7%
trackSpansWithFields 488.83 us 473.52 us +3.2%
trackSpansWithoutFields 7.96 us 7.84 us +1.5%
webViewBridgeBridgeReady 7.97 us 8.16 us -2.3%
webViewBridgeCustomLog 9.10 us 9.26 us -1.7%
webViewBridgeInvalidJson 164.82 us 120.55 us +36.7%
webViewBridgeWebVitalCLS 21.01 us 20.08 us +4.7%

@murki
Copy link
Copy Markdown
Contributor

murki commented Apr 9, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 9, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from that review thread in 217848b:

  1. Added signalNumber: Int = 0 default to IssueReporterProcessor override for backward compatibility with existing call sites.
  2. Moved .use {} outside the convertExitReasonToFbsReportType call in IssueReporter so the stream is always closed even when the exit reason is unrecognized.
  3. Added ?: "Native crash" fallback in createErrorOffset to prevent null being passed to FlatBufferBuilder.createString().
  4. Reworded CHANGELOG entry to clarify this is specific to native crash reports without tombstone data on API 30.

Copilot finished work on behalf of murki April 9, 2026 01:23
@murki
Copy link
Copy Markdown
Contributor

murki commented Apr 9, 2026

@copilot after your changes the build broke with the following error, go fix it:

e: file:///home/runner/work/capture-sdk/capture-sdk/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/reports/processor/IssueReporterProcessor.kt:114:29 An overriding function is not allowed to specify default values for its parameters
Finished executing kotlin compiler using DAEMON strategy

> Task :capture:compileReleaseKotlin FAILED

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 9, 2026

@copilot after your changes the build broke with the following error, go fix it:

e: file:///home/runner/work/capture-sdk/capture-sdk/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/repo...

Removed = 0 default from the overriding signalNumber parameter in IssueReporterProcessor (Kotlin doesn't allow default values on override parameters) and updated all test call sites to pass signalNumber = 0 explicitly. See b1075f5.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dl.google.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx2048M -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of murki April 9, 2026 01:41
Co-Authored-By: murki <216735+murki@users.noreply.github.com>
@FranAguilera FranAguilera force-pushed the copilot/implement-skeleton-crash-reports branch from b1075f5 to 90742b7 Compare April 9, 2026 10:00
@FranAguilera FranAguilera changed the title BIT-7817: Skeleton crash reports for native crashes on API level 30 [Android] Send Native Crash reports with empty stacktraces below OS 12 Apr 9, 2026
@FranAguilera FranAguilera force-pushed the copilot/implement-skeleton-crash-reports branch 4 times, most recently from 2644123 to 6686aa2 Compare April 9, 2026 11:19
@FranAguilera FranAguilera force-pushed the copilot/implement-skeleton-crash-reports branch from 6686aa2 to 5bb89e5 Compare April 9, 2026 11:22
@FranAguilera FranAguilera changed the title [Android] Send Native Crash reports with empty stacktraces below OS 12 [Android] Send Native Crash reports with empty stacktraces for OS 11 Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants